package com.zhang.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zhang.client.ProductFeignClient;
import com.zhang.constant.RedisConst;
import com.zhang.entity.CartInfo;
import com.zhang.entity.SkuInfo;
import com.zhang.mapper.CartInfoMapper;
import com.zhang.service.AsyncCartInfoService;
import com.zhang.service.CartInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhang.util.AuthContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车表 用户登录系统时更新冗余 服务实现类
 * </p>
 *
 * @author zbw
 * @since 2022-04-19
 */
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {
    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private AsyncCartInfoService asyncCartInfoService;
    //加入购物车
    @Override
    public void addToCart(String oneOfUserId, Long skuId, Integer skuNum) {
        //a.查询数据库中是否有购物车信息
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",oneOfUserId);
        wrapper.eq("sku_id",skuId);
        CartInfo existCartInfo = baseMapper.selectOne(wrapper);
        if (existCartInfo!=null){
            //把原来的数量加上传递过来的数量
            existCartInfo.setSkuNum(existCartInfo.getSkuNum()+skuNum);
            //更新加入购物车商品的实时价格
            BigDecimal skuPrice = productFeignClient.getSkuPrice(skuId);
            existCartInfo.setCartPrice(skuPrice);
            //baseMapper.updateById(existCartInfo);
            asyncCartInfoService.updateCartInfo(existCartInfo);
        }else {
            existCartInfo = new CartInfo();
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            existCartInfo.setUserId(oneOfUserId);
            existCartInfo.setSkuId(skuId);
            //添加购物车的时候的价格
            existCartInfo.setCartPrice(skuInfo.getPrice());
            existCartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            existCartInfo.setSkuName(skuInfo.getSkuName());
            existCartInfo.setSkuNum(skuNum);
            //默认勾选上该商品
            existCartInfo.setIsChecked(1);
            existCartInfo.setRealTimePrice(productFeignClient.getSkuPrice(skuId));
            //baseMapper.insert(existCartInfo);
            asyncCartInfoService.saveCartInfo(existCartInfo);
        }
        //b.往redis里面怼一份
        String userCartKey= getUserCartKey(oneOfUserId);
        redisTemplate.boundHashOps(userCartKey).put(skuId.toString(),existCartInfo);
    }

    private String getUserCartKey(String oneOfUserId) {
        return RedisConst.USER_KEY_PREFIX+oneOfUserId+RedisConst.USER_CART_KEY_SUFFIX;
    }

    //2.购物车列表
    @Override
    public List<CartInfo> getCartList(HttpServletRequest request) {
        String userId = AuthContextHolder.getUserId(request);
        String userTempId = AuthContextHolder.getUserTempId(request);
        List<CartInfo> cartInfoList=new ArrayList<>();
        //1.未登录
        if (StringUtils.isEmpty(userId)&&!StringUtils.isEmpty(userTempId)){
            cartInfoList=queryCartInfoFromDbToRedis(userTempId);
        }
        //2.已登录 &&!StringUtils.isEmpty(userTempId)
        if(!StringUtils.isEmpty(userId)){
            //a.看是否有未登录的购物项，如果有合并，否则只查登录用户的购物车信息
            List<CartInfo> noLoginCartInfoList=queryCartInfoFromDbToRedis(userTempId);
            if (!CollectionUtils.isEmpty(noLoginCartInfoList)){
                //b.合并已登录和未登录的购物项
                mergeCartInfoList(userId,userTempId);
                //c.删除合并之后临时用户购物车信息
                cartInfoList=deleteOldDataLoadNewData(userId,userTempId);
            }else { //
                //先删除原来的缓存
                String userCartKey = getUserCartKey(userId);
                redisTemplate.delete(userCartKey);
                //再查询数据库
                cartInfoList = queryCartInfoFromDbToRedis(userId);
            }
        }
        return cartInfoList;
    }

    //勾选商品
    @Override
    public void checkCart(String oneOfUserId, Long skuId, Integer isChecked) {
        //a.从redis中查询数据并修改
        String userCartKey = getUserCartKey(oneOfUserId);
        BoundHashOperations operations = redisTemplate.boundHashOps(userCartKey);
        //看redis中是否有该商品
        if (operations.hasKey(skuId.toString())){
            CartInfo redisCartInfo = (CartInfo) operations.get(skuId.toString());
            redisCartInfo.setIsChecked(isChecked);
            //更新到redis中
            operations.put(skuId.toString(),redisCartInfo);
            //设置过期时间
            setCartKeyExpire(userCartKey);
        }
        //b.从数据库中查询记录修改
        asyncCartInfoService.checkDbCart(oneOfUserId,skuId,isChecked);
    }

    //从数据库中查询记录修改
    private void checkDbCart(String oneOfUserId, Long skuId, Integer isChecked) {
        //update cart_info set is_checked=1 where user_id=xxx and sku_id=xxx
        CartInfo cartInfo = new CartInfo();
        cartInfo.setIsChecked(isChecked);
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",oneOfUserId);
        wrapper.eq("sku_id",skuId);
        baseMapper.update(cartInfo,wrapper);
    }

    //删除购物车
    @Override
    public void deleteCart(String oneOfUserId, Long skuId) {
        //a.删除redis里面的内容
        String userCartKey = getUserCartKey(oneOfUserId);
        BoundHashOperations operations = redisTemplate.boundHashOps(userCartKey);
        //看redis中是否有该商品
        if (operations.hasKey(skuId.toString())){
            operations.delete(skuId.toString());
        }
        //b.删除数据库里面的内容
        asyncCartInfoService.deleteDbCart(oneOfUserId,skuId);
    }

    //删除数据库里面的内容
    private void deleteDbCart(String oneOfUserId, Long skuId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",oneOfUserId);
        wrapper.eq("sku_id",skuId);
        baseMapper.delete(wrapper);
    }

    //查询选中的商品信息--送货清单
    @Override
    public List<CartInfo> getSelectedCartInfo(String userId) {
        String userCartKey = getUserCartKey(userId);
        List<CartInfo> redisCartInfoList = redisTemplate.opsForHash().values(userCartKey);
        List<CartInfo> selectedCartInfo = new ArrayList<>();
        if (!CollectionUtils.isEmpty(redisCartInfoList)){
            for (CartInfo cartInfo : redisCartInfoList) {
                //判断该商品是否有勾选
                if (cartInfo.getIsChecked()==1){
                    selectedCartInfo.add(cartInfo);
                }
            }
        }
        return selectedCartInfo;
    }


    //删除合并之后临时用户购物车信息
    private List<CartInfo> deleteOldDataLoadNewData(String userId, String userTempId) {
        //删除数据库里面的老数据
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userTempId);
        baseMapper.delete(wrapper);
        //删除redis里面的缓存数据
        String userIdCartKey = getUserCartKey(userId);
        String userTempIdCartKey = getUserCartKey(userTempId);
        redisTemplate.delete(userIdCartKey);
        redisTemplate.delete(userTempIdCartKey);
        //重新加载数据到redis中
        List<CartInfo> cartInfoList = queryCartInfoFromDbToRedis(userId);
        return cartInfoList;
    }

    //合并已登录和未登录的购物项
    private void mergeCartInfoList(String userId, String userTempId) {
        //未登录的
        List<CartInfo> noLoginCartInfoList=queryCartInfoFromDbToRedis(userTempId);
        //已登录
        List<CartInfo> loginCartInfoList=queryCartInfoFromDbToRedis(userId);
//          for (CartInfo noLoginCart : noLoginCartInfoList) {
//            for (CartInfo loginCart : loginCartInfoList) {
//                if(noLoginCart.getSkuId().equals(loginCart.getSkuId())){
//
//                }
//            }
//        }
        Map<Long,CartInfo> loginCartInfoMap=loginCartInfoList.stream().collect(Collectors.toMap(CartInfo::getSkuId,cartInfo -> {
            return cartInfo;
        }));
        for (CartInfo noLoginCartInfo : noLoginCartInfoList) {
            Long noLoginSkuId = noLoginCartInfo.getSkuId();
            //对比skuId是否相同 如果相同代表登录项里面有该购物项
            if (loginCartInfoMap.containsKey(noLoginSkuId)){
                CartInfo loginCartInfo = loginCartInfoMap.get(noLoginSkuId);
                //对数量进行加操作
                loginCartInfo.setSkuNum(loginCartInfo.getSkuNum()+noLoginCartInfo.getSkuNum());
                //当未登录的时候如果该商品没有勾选 合并之后就需要勾选
                if (noLoginCartInfo.getIsChecked()==1){
                    loginCartInfo.setIsChecked(1);
                }
                //更新数据库
                baseMapper.updateById(loginCartInfo);
            }else {
                //如果已登录里面没有该购物项
                noLoginCartInfo.setUserId(userId);
                baseMapper.updateById(noLoginCartInfo);
            }
        }
    }

    //未登录情况下查询购物车信息
    private List<CartInfo> queryCartInfoFromDbToRedis(String oneOfUserId) {
        String userCartKey = getUserCartKey(oneOfUserId);
        List<CartInfo> cartInfoList = redisTemplate.boundHashOps(userCartKey).values();
        //如果缓存中没有值
        if (CollectionUtils.isEmpty(cartInfoList)){
            QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id",oneOfUserId);
            cartInfoList=baseMapper.selectList(wrapper);
            Map<String, CartInfo> cartMap = new HashMap<>();
            for (CartInfo cartInfo : cartInfoList) {
                //redisTemplate.boundHashOps(userCartKey).put(cartInfo.getSkuId().toString(),cartInfo);
                cartMap.put(cartInfo.getSkuId().toString(),cartInfo);
            }
            redisTemplate.boundHashOps(userCartKey).putAll(cartMap);
            //设置redis里面购物车信息过期时间
            setCartKeyExpire(userCartKey);
        }
        return cartInfoList;
    }

    private void setCartKeyExpire(String userCartKey) {
        redisTemplate.expire(userCartKey,RedisConst.USER_CART_EXPIRE, TimeUnit.SECONDS);
    }

}
